# 종류별 테스트 작성하기

이번 강의에서는 파이썬으로 유닛, 통합, E2E 테스트를 테스트 코드로 작성해봅시다.
시나리오로 간단한 쇼핑몰 웹 사이트에서 백엔드의 로그인 기능을 개발하고 있다고 가정하겠습니다.

# 유닛 테스트

로그인 기능에는 다음처럼 로그인 인증을 마친 유저에게 응답으로 줄 토큰을 생성하는 함수를 사용합니다.

def create_token(user_id: str) -> str:
    return user_id + "_verified"

물론 실제로 토큰 발급을 절대 위와 같이 하지 않습니다. 코드 예제를 심플하게 가져가기 위해서 간략히 표현했습니다.

유닛 테스트는 함수나 메서드 같이 작은 단위의 코드에서 입출력의 결과가 올바른지를 확인하는 테스트입니다. 위 함수는 유닛 테스트를 하기 좋은 대상입니다.
다음처럼 유닛 테스트 코드를 작성해볼 수 있습니다.

def test_create_token():
    actual = create_token("grab")
    expected = "grab_verified"
    assert actual == expected

# 통합 테스트

로그인 기능에는 다음처럼 로그인 로직을 수행하는 함수를 사용합니다.

def login(user_id: str, user_password: str) -> str:
    user_repository = UserRepository()  # DB와 연동되어 User 정보를 저장하고 불러오는 객체
    user = user_repository.find_by_id(user_id)
    if user.id == user_id and user.password == user_password:
        return create_token(user_id)
    else:
        raise Exception("로그인 인증에 실패했습니다.")

통합 테스트는 여러 요소를 통합한 프로세스를 검증하는 테스트라고 했습니다. login() 함수는 user_repositorycreate_token() 에 의존하고 있는 통합적인 로직을 가진 함수입니다. 이 함수에 대해 다음처럼 통합 테스트 코드를 작성해볼 수 있습니다.

def test_login_successful():
    # given
    user_id = "grab"
    user_password = "1234"
    
    # when
    actual = login(user_id, user_password)
    
    # then
    assert actual == "grab_verified"
    
    
def test_login_failed():
    # given
    user_id = "grab"
    user_password = "wrong password"
    
    # when & then
    with pytest.raises(Exception):
        login(user_id, user_password)

위 코드가 성공하려면 login() 함수 내부의 UserRepository 인스턴스와 create_token() 함수 역시 잘 작동해야 합니다. 이처럼 통합 테스트는 의존성 있는 객체들의 정상 작동 여부까지 포함하는 테스트입니다.

일반적으로 통합테스트는 외부 의존성을 포함하고 있는 경우가 많습니다. 하지만 테스트 환경은 운영 환경과 분리되어야 합니다. 예를 들어, 테스트 코드를 실행할 때 운영 DB에 연동하면 안됩니다.

따라서 테스트에서 재현할 수 없는 외부 의존성 (운영 데이터베이스, 운영 API 서버 등)은 테스트 더블을 사용합니다. 테스트 더블 바로가기

# E2E 테스트

실제로 유저는 HTTP 요청으로 로그인을 요청하게 됩니다. 따라서 애플리케이션은 다음과 같은 웹 인터페이스를 제공해야 합니다.

from fastapi import FastAPI

app = FastAPI()

class LoginRequest(BaseModel):
    id: str
    password: str

@app.get("/login")
def login_endpoint(req: LoginRequest):
    token = login(user_id=req.id, user_password=req.password)
    return {
        "token": token
    }

E2E 테스트는 최종 사용자 입장에서의 테스트입니다. 다음처럼 서버를 localhost:8000 에 실행시킨 상황이라고 생각하고, 서버에 요청을 로그인 요청을 보내고 응답받는 테스트 코드를 작성합니다.

import requests

def test_login_endpoint():
    # given
    api_host = "localhost:8000"
    payload = {
        "id": "grab",
        "password": "1234"
    }
    
    # when
    res = requests.post(url=f"{api_host}/login", json=payload)
    
    # then
    assert res.data() == {
        "token": "grab_verified"
    }

위 테스트 코드가 성공하려면 localhost:8000 에 실행한 서버가 잘 작동되어야 합니다. 이처럼 E2E 테스트는 서버 내부 동작은 전혀 관여하지 않은 채, 철저히 엔드 유저 입장에서 서버를 이용하는 시나리오대로 테스트해보는 것입니다.

Last Updated: 2/20/2022, 1:51:31 PM

CC-BY-NC-ND-4.0 Licensed | Copyright © 2021-present Grab